React use-hooket til ressourcestyring: Optimering af ressourcers livscyklus for maksimal ydeevne | MLOG | MLOG

Forklaring:

Eksempel 2: Håndtering af WebSocket-forbindelser

Dette eksempel viser, hvordan man håndterer en WebSocket-forbindelse ved hjælp af "use"-hooket og en brugerdefineret ressource-indpakning.

            import React, { useState, useEffect, use } from 'react';

const createWebSocketResource = (url) => {
  let socket;
  let status = 'pending';
  let messageQueue = [];
  let listeners = [];

  const connect = () => {
    return new Promise((resolve, reject) => {
      socket = new WebSocket(url);

      socket.onopen = () => {
        status = 'connected';
        resolve();
        // Send beskeder i kø
        messageQueue.forEach(msg => socket.send(msg));
        messageQueue = [];
      };

      socket.onerror = (error) => {
        status = 'error';
        reject(error);
      };

      socket.onmessage = (event) => {
        listeners.forEach(listener => listener(event.data));
      };

      socket.onclose = () => {
        status = 'closed';
        listeners = []; // Ryd listeners for at undgå hukommelseslækager
      };
    });
  };

  const promise = connect();

  return {
    read() {
      use(promise);
    },
    send(message) {
      if (status === 'connected') {
        socket.send(message);
      } else {
        messageQueue.push(message);
      }
    },
    subscribe(listener) {
      listeners.push(listener);
      return () => {
        listeners = listeners.filter(l => l !== listener);
      };
    },
    close() {
        if (socket && socket.readyState !== WebSocket.CLOSED) {
            socket.close();
        }
    }
  };
};

function WebSocketComponent({ url }) {
  const socketResource = createWebSocketResource(url);
  // Suspender indtil forbundet
  socketResource.read();
  const [message, setMessage] = useState('');
  const [receivedMessages, setReceivedMessages] = useState([]);

  useEffect(() => {
    const unsubscribe = socketResource.subscribe(data => {
      setReceivedMessages(prevMessages => [...prevMessages, data]);
    });
    return () => {
        unsubscribe();
        socketResource.close();
    };
  }, [socketResource]);

  const sendMessage = () => {
    socketResource.send(message);
    setMessage('');
  };

  return (
    
setMessage(e.target.value)} />
Received Messages:
    {receivedMessages.map((msg, index) => (
  • {msg}
  • ))}
); } function App() { return ( Connecting to WebSocket...
}> ); } export default App;

Forklaring:

Eksempel 3: Håndtering af filhåndtag

Dette eksempel illustrerer ressourcestyring med "use"-hooket ved hjælp af NodeJS-filhåndtag (Dette vil kun fungere i et NodeJS-miljø og er beregnet til at vise koncepter for ressourcers livscyklus).

            // Dette eksempel er designet til et NodeJS-miljø

const fs = require('node:fs/promises');
import React, { use } from 'react';

const createFileHandleResource = async (filePath) => {
  let fileHandle;

  const openFile = async () => {
    fileHandle = await fs.open(filePath, 'r');
    return fileHandle;
  };

  const promise = openFile();

  return {
    read() {
      return use(promise);
    },
    async close() {
      if (fileHandle) {
        await fileHandle.close();
        fileHandle = null;
      }
    },
    async readContents() {
      const handle = use(promise);
      const buffer = await handle.readFile();
      return buffer.toString();
    }
  };
};


function FileViewer({ filePath }) {
  const fileHandleResource = createFileHandleResource(filePath);
  const contents = fileHandleResource.readContents();

  React.useEffect(() => {
    return () => {
      // Oprydning, når komponenten afmonteres
      fileHandleResource.close();
    };
  }, [fileHandleResource]);

  return (
    

File Contents:

{contents}
); } // Eksempel på brug async function App() { const filePath = 'example.txt'; await fs.writeFile(filePath, 'Hello, world!\nThis is a test file.'); return (
); } export default App;

Forklaring:

Avancerede teknikker: Error Boundaries, ressource-pooling og Server Components

Ud over de grundlæggende eksempler kan "use"-hooket kombineres med andre React-funktioner for at implementere mere sofistikerede strategier for ressourcestyring.

Error Boundaries: Elegant fejlhåndtering

Error Boundaries er React-komponenter, der fanger JavaScript-fejl hvor som helst i deres undertræ af komponenter, logger disse fejl og viser en fallback-brugergrænseflade i stedet for at lade hele komponenttræet gå ned. Når du bruger "use"-hooket, er det afgørende at indpakke dine komponenter med Error Boundaries for at håndtere potentielle fejl under datahentning eller ressourceinitialisering.

            import React, { Component } from 'react';

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Opdater tilstand, så næste rendering vil vise fallback-UI'en.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // Du kan også logge fejlen til en fejlrapporteringstjeneste
    console.error(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // Du kan rendere enhver brugerdefineret fallback-UI
      return 

Something went wrong.

; } return this.props.children; } } function App() { return ( Loading...
}> ); }

Ressource-pooling: Optimering af genbrug af ressourcer

I nogle scenarier kan det være dyrt at oprette og ødelægge ressourcer hyppigt. Ressource-pooling indebærer at vedligeholde en pulje af genanvendelige ressourcer for at minimere omkostningerne ved oprettelse og ødelæggelse af ressourcer. Selvom "use"-hooket ikke i sig selv implementerer ressource-pooling, kan det bruges i forbindelse med en separat implementering af en ressourcepulje.

Overvej en pulje af databaseforbindelser. I stedet for at oprette en ny forbindelse for hver anmodning kan du vedligeholde en pulje af forud-etablerede forbindelser og genbruge dem. "use"-hooket kan bruges til at styre erhvervelse og frigivelse af forbindelser fra puljen.

(Konceptuelt eksempel - Implementering varierer afhængigt af den specifikke ressource og pooling-bibliotek):

            // Konceptuelt eksempel (ikke en komplet, køreklar implementering)

import React, { use } from 'react';
// Antag, at et bibliotek til databaseforbindelsespuljer eksisterer
import { getConnectionFromPool, releaseConnectionToPool } from './dbPool';

const createDbConnectionResource = () => {
  let connection;

  const acquireConnection = async () => {
    connection = await getConnectionFromPool();
    return connection;
  };

  const promise = acquireConnection();

  return {
    read() {
      return use(promise);
    },
    release() {
      if (connection) {
        releaseConnectionToPool(connection);
        connection = null;
      }
    },
    query(sql) {
      const conn = use(promise);
      return conn.query(sql);
    }
  };
};

function MyDataComponent() {
  const dbResource = createDbConnectionResource();

  React.useEffect(() => {
    return () => {
      dbResource.release();
    };
  }, [dbResource]);

  const data = dbResource.query('SELECT * FROM my_table');
  return 
{data}
; }

React Server Components (RSC'er): Det naturlige hjem for "use"-hooket

"use"-hooket blev oprindeligt designet til React Server Components. RSC'er eksekveres på serveren, hvilket giver dig mulighed for at hente data og udføre andre serverside-operationer uden at sende kode til klienten. Dette forbedrer ydeevnen betydeligt og reducerer størrelsen på klientsidens JavaScript-bundles.

I RSC'er kan "use"-hooket bruges til direkte at hente data fra databaser eller API'er uden behov for klientsidens hente-biblioteker. Dataene hentes på serveren, og den resulterende HTML sendes til klienten, hvor den hydreres af React.

Når du bruger "use"-hooket i RSC'er, er det vigtigt at være opmærksom på begrænsningerne i RSC'er, såsom manglen på klientside-tilstand og hændelseshåndterere. Dog kan RSC'er kombineres med klientside-komponenter for at skabe kraftfulde og effektive applikationer.

Bedste praksis for effektiv ressourcestyring med "use"

For at maksimere fordelene ved "use"-hooket til ressourcestyring skal du følge disse bedste praksisser:

Almindelige faldgruber og hvordan man undgår dem

Selvom "use"-hooket tilbyder talrige fordele, er det vigtigt at være opmærksom på potentielle faldgruber og hvordan man undgår dem.

Konklusion: Omfavnelse af "use"-hooket for optimerede React-applikationer

Reacts "use"-hook repræsenterer et betydeligt fremskridt inden for ressourcestyring i React-applikationer. Ved at forenkle håndtering af asynkrone data, automatisere ressourceoprydning og integrere problemfrit med Suspense giver det udviklere mulighed for at bygge mere højtydende, vedligeholdelsesvenlige og brugervenlige applikationer.

Ved at forstå kernekoncepterne, udforske praktiske eksempler og følge bedste praksis kan du effektivt udnytte "use"-hooket til at optimere ressourcers livscyklus og frigøre det fulde potentiale i dine React-applikationer. I takt med at React fortsætter med at udvikle sig, vil "use"-hooket utvivlsomt spille en stadig vigtigere rolle i at forme fremtiden for ressourcestyring i React-økosystemet.